import re
import os
import json
import requests
from datetime import datetime

revert_key_list = [
  'HOST_HTTP_SESSION_COUNT',
  'HOST_ACCESS_IP_COUNT',
  'HOST_WEB_DOMAIN_COUNT',
  'HOST_NEW_CALL_COUNT',
  'HOST_ACCESS_SRC_IP_COUNT',
  'HOST_SQL_ADD_COUNT',
  'HOST_SQL_ADD_SIZE_BYTES',
  'HOST_MAX_BUSI_LOAD'
]

def calc_resource_index(cpu_usage, mem_usage, storage_usage):
  # CPU 资源利用率指数
  cpu_score = 100 * (1 - abs(cpu_usage - 50) / 50)
  
  # 内存资源利用率指数
  if 30 <= mem_usage <= 70: mem_score = 100
  elif mem_usage < 30: mem_score = 100 - ((0.3 - mem_usage / 100) * 100 / 0.3)
  else: mem_score = 100 - ((mem_usage / 100 - 0.7) * 100 / 0.3)
  if mem_score < 0: mem_score = 0

  # 存储资源利用率指数
  if 30 <= storage_usage <= 70: storage_score = 100
  elif storage_usage < 30: storage_score = 100 - ((0.3 - storage_usage / 100) * 100 / 0.3)
  else: storage_score = 100 - ((storage_usage / 100 - 0.7) * 100 / 0.3)
  if storage_score < 0: storage_score = 0

  # 计算最终的资源利用率指数 S
  S = cpu_score * 0.5 + mem_score * 0.3 + storage_score * 0.2
  return S

def calc_performance_index(http_response_time, error_400_rate, error_500_rate):
  # HTTP 响应时间指数
  if http_response_time <= 1: t = 100
  elif http_response_time >= 3: t = 0
  else: t = (3 - http_response_time) / 2 * 100

  # HTTP 400 错误率指数
  if error_400_rate <= 1: r400 = 100
  elif error_400_rate >= 5: r400 = 0
  else: r400 = (5 - error_400_rate) / 4 * 100

  # HTTP 500 错误率指数
  if error_500_rate <= 0.1: r500 = 100
  elif error_500_rate >= 1: r500 = 0
  else: r500 = (1 - error_500_rate) / 0.9 * 100

  # 计算最终的业务性能指数 P
  P = t * 0.4 + r400 * 0.3 + r500 * 0.3
  return P

def calc_database_index(sql_response_time, sql_return_code_rate):
  # SQL 响应时间指数
  if sql_response_time <= 1: t = 100
  elif sql_response_time >= 3: t = 0
  else: t = (3 - sql_response_time) / 2 * 100

  # SQL 返回码指数
  if sql_return_code_rate <= 0.5: r = 100
  elif sql_return_code_rate >= 5: r = 0
  else: r = (5 - sql_return_code_rate) / 4.5 * 100

  # 计算最终的数据库效能指数 D
  D = t * 0.7 + r * 0.3
  return D

def calc_network_index(network_latency, packet_loss_rate, is_external=True):
  # 网络时延指数
  if is_external:
    if network_latency <= 50: latency_score = 100
    elif network_latency >= 200: latency_score = 0
    else: latency_score = (200 - network_latency) / 150 * 100

    # 丢包率指数
    if packet_loss_rate <= 1: loss_score = 100
    elif packet_loss_rate >= 5: loss_score = 0
    else: loss_score = (5 - packet_loss_rate) / 4 * 100
  else:
    if network_latency <= 10: latency_score = 100
    elif network_latency >= 100: latency_score = 0
    else: latency_score = (100 - network_latency) / 90 * 100

    # 丢包率指数
    if packet_loss_rate <= 0.1: loss_score = 100
    elif packet_loss_rate >= 1: loss_score = 0
    else: loss_score = (1 - packet_loss_rate) / 0.9 * 100

  # 计算最终的网络性能指数 N
  N = latency_score * 0.4 + loss_score * 0.6
  return N

def calc_efficiency_score(T, S, P, D=None, N=None, weight_resource=0.7, weight_performance=0.3):
  X = T * (S * weight_resource) * (P * weight_performance)
  if D is not None: X *= D
  if N is not None: X *= N
  return X

# 还原错误KEY
def revert_err_keys(host_yes, host_yes_cpu, host_err, host_err_cpu):
  for revert_key in revert_key_list:
    host_yes_key_ratio = host_yes[revert_key] / host_yes_cpu
    host_err[revert_key] = host_err_cpu * host_yes_key_ratio
    # 如果因为乘了CPU比率形式小数化整处理
    if host_err[revert_key] >= 1:
      host_err[revert_key] = int(host_err[revert_key])
  
def calc_cloud_score(host_yes, host_err):
  # 重新计算效能
  cloud_resource_index = calc_resource_index(host_err['HOST_CPU_AVG'], host_err['HOST_MEM_AVG'], host_err['HOST_DISK_AVG'])
  cloud_performance_index = calc_performance_index(host_err['HOST_APP_RESPONSE_AVG'], host_err['HOST_RETCODE_4xx_ERR_RATIO'], host_err['HOST_RETCODE_5xx_ERR_RATIO'])
  cloud_database_index = calc_database_index(host_err['HOST_SQL_RESPONSE_AVG'], host_err['HOST_RETCODE_SQL_ERR_RATIO'])
  cloud_network_index = calc_network_index(host_err['HOST_NET_DELAY_AVG'], host_err['HOST_RETRANS_RATIO'])
  
  cpu_core = float(host_err['HOST_CPU_CORE'])
  cpu_max  = float(host_err['HOST_CPU_MAX'])
  tcp_session_count = float(host_err["HOST_TCP_SESSION_COUNT"])
  
  if int(cpu_core) <= 0: cpu_core = 1.0
  if int(cpu_max)  <= 0: cpu_max  = 1.0
  
  energy_efficiency_ratio = tcp_session_count / (cpu_core * cpu_max)
  cloud_efficiency = calc_efficiency_score(energy_efficiency_ratio, cloud_resource_index, cloud_performance_index)
  
  host_err['HOST_ENERGY_EFFICIENCY_RATIO'] = energy_efficiency_ratio
  host_err['HOST_RESOURCE_INDEX'] = cloud_resource_index
  host_err['HOST_PERFORMANCE_INDEX'] = cloud_performance_index
  host_err['HOST_DATABASE_INDEX'] = cloud_database_index
  host_err['HOST_NETWORK_INDEX'] = cloud_network_index
  host_err['HOST_EFFICIENCY_SCORE'] = cloud_efficiency 

def revert_result_file(err_file, yes_file):
  dict_err = json.load(open(err_file, 'r'))
  dict_yes = json.load(open(yes_file, 'r'))
  
  for host, metrics in dict_err.items():
    host_err = dict_err[host]
    host_err_cpu = host_err['HOST_CPU_AVG']

    # 还原ARCH_SIZE，还原HOST_LIVE_BYTES
    host_err['ARCH_SIZE'] = 600
    host_err['HOST_LIVE_BYTES'] = host_err['HOST_BYTES']

    # 根据HOST_LIVE_BYTES还原HOST_NORMAL_RATIO
    host_err['HOST_NORMAL_RATIO'] = 0
    if host_err['HOST_LIVE_BYTES'] > 10240:
      host_err['HOST_NORMAL_RATIO'] = 1

    # 内存使用有可能不合理
    if host_err['HOST_MEM'] > 100 or host_err['HOST_MEM_MAX'] > 100:
      host_err['HOST_MEM']     = host_err['HOST_MEM']     / float(host_err['HOST_MEM_TOTAL'])
      host_err['HOST_MEM_AVG'] = host_err['HOST_MEM_AVG'] / float(host_err['HOST_MEM_TOTAL'])
      host_err['HOST_MEM_MAX'] = host_err['HOST_MEM_MAX'] / float(host_err['HOST_MEM_TOTAL'])

    # 数据库新增数据量字段名更改
    if 'HOST_SQL_ADD_SIZE' in host_err:
      host_err['HOST_SQL_ADD_SIZE_BYTES'] = host_err['HOST_SQL_ADD_SIZE']
      host_err.pop('HOST_SQL_ADD_SIZE')

    # 如果错误主机不在正确主机里，无法还原
    if host not in dict_yes: continue

    host_yes = dict_yes[host]
    host_yes_cpu = host_yes['HOST_CPU_AVG']
    if 0 == host_yes_cpu or 0 == host_err_cpu: continue

    revert_err_keys(host_yes, host_yes_cpu, host_err, host_err_cpu)
    calc_cloud_score(host_yes, host_err)

  return dict_err

def send_gelf_http_message(url, session, message):
  headers = {'Content-Type': 'application/json'}
  try:
    session.post(url, data=message, headers=headers)
  except requests.exceptions.RequestException as e:
    print(f"send message error: {e}")

def send_result(arch_time, result, protocol):
  result_len = len(result)

  # 发送到GELF HTTP 或者 UDP
  if protocol == 'http':
    gelf_url = f'http://127.0.0.1:12201/gelf'
    with requests.Session() as session:
      for key, val in result.items():
        val['timestamp'] = arch_time
        val['HOST_ACCESS_IP_COUNT'] = int(val['HOST_ACCESS_IP_COUNT'])
        val['HOST_ACCESS_SRC_IP_COUNT'] = int(val['HOST_ACCESS_SRC_IP_COUNT'])
        message = json.dumps(val)
        send_gelf_http_message(gelf_url, session, message.encode('utf-8'))
  else:
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as gelf_udp:
      for key, val in merge_result.items():
        val['timestamp'] = arch_time
        val['HOST_ACCESS_IP_COUNT'] = int(val['HOST_ACCESS_IP_COUNT'])
        val['HOST_ACCESS_SRC_IP_COUNT'] = int(val['HOST_ACCESS_SRC_IP_COUNT'])
        message = json.dumps(val)
        gelf_udp.sendto(message.encode('utf-8'), ('127.0.0.1', 12201))

  print(f'MERGE: send {arch_time} result, {result_len} hosts ...')

yes_date = '2024-08-28'
source_dir = '/uniarch'

err_files = [f for f in os.listdir(source_dir) if f.endswith('.json')]
err_files.sort()

for err_file in err_files:
  err_path = os.path.join(source_dir, err_file)
  yes_path  = re.sub(r'\d{4}-\d{2}-\d{2}', yes_date, err_path)

  err_date_str = err_path.replace('/uniarch/', '').replace('.json', '')
  arch_timestamp = datetime.strptime(err_date_str, "%Y-%m-%d %H:%M:%S").timestamp()

  print(f'process {err_path} ({arch_timestamp}) with {yes_path} ...')
  result = revert_result_file(err_path, yes_path)
  send_result(arch_timestamp, result, 'http')
